﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Globalization;
using System.Resources;

namespace DirectorySlicer
{
    public partial class Form1 : Form
    {
        /// <summary>
        /// this class is intended to signal if the START button is ready to be active to be pressed.
        /// usage: remove the boolean of a component and insert a new boolean, dependend of its ready-status
        /// </summary>
        internal class DictionarySelftesting
        {
            private Dictionary<Component, bool> dict = new Dictionary<Component, bool>(3);
            private Button button_start;

            public DictionarySelftesting(Button b)
            {
                this.button_start = b;
            }

            public void Add(Component c, bool b)
            {
                dict.Add(c, b);
                check();
            }

            public void Remove(Component c)
            {
                dict.Remove(c);
            }

            private void check()
            {
                // three components have to be ready at once
                if (dict.Count != 3)
                {
                    button_start.Enabled = false;
                    return;
                }
                foreach (bool b in dict.Values)
                    if (b == false)
                    {
                        button_start.Enabled = false;
                        return;
                    }
                button_start.Enabled = true;
            }
        }


        private DictionarySelftesting beforeStartChecks;
        private List<String> presets = new List<string>();
        private const String CD74 = "CD-74 (650MB)";
        private const String CD80 = "CD-80 (700MB)";
        private const String CD90 = "CD-90 (800MB)";
        private const String DVD5 = "DVD-5 (4.7GB)";
        private const String DVD9 = "DVD-9 (8.5GB)";
        private const String BD   = "BD    (25GB)";
        private const String BDDL = "BD-DL (50GB)";
        
        public Form1()
        {
            InitializeComponent();
            progressBar.Step = 1;
            beforeStartChecks = new DictionarySelftesting(button_START);
            presets.Add("");
            presets.Add(CD74);
            presets.Add(CD80);
            presets.Add(CD90);
            presets.Add(DVD5);
            presets.Add(DVD9);
            presets.Add(BD);
            presets.Add(BDDL);
            dropdown_preset.DataSource = presets;
            beforeStartChecks.Add(textBox_sourcePath, false);
            beforeStartChecks.Add(textBox_destPath, false);
            beforeStartChecks.Add(textBox_size, false);
            comboBox_KindOfSize.SelectedIndex = 0;
            Logger.SetLogger(textBox_log, progressBar);
            Logger.Log("program ready");
        }

        private void button1_sourceFolder_Click(object sender, EventArgs e)
        {
            folderBrowserDialog1.ShowDialog();
            textBox_sourcePath.Text = folderBrowserDialog1.SelectedPath;
        }

        private void button_destFolder_Click(object sender, EventArgs e)
        {
            folderBrowserDialog2.ShowDialog();
            textBox_destPath.Text = folderBrowserDialog2.SelectedPath;
        }

        //check if path configuration allows to activate the hardlink option
        private void sourceOrPathChanged(object sender, EventArgs e)
        {
            if (textBox_sourcePath.Text != ""
                && textBox_destPath.Text != ""
                && textBox_sourcePath.Text.ToUpper()[0] == textBox_destPath.Text.ToUpper()[0]
                && (new DriveInfo(textBox_sourcePath.Text[0].ToString()).DriveFormat.ToString()) == "NTFS")
            {
                checkBox_HardLinks.Enabled = true;
                checkBox_HardLinks.Checked = true;
            }
            else
            {
                checkBox_HardLinks.Enabled = false;
                checkBox_HardLinks.Checked = false;
            }
        }

        private void textBox_sourcePath_TextChanged(object sender, EventArgs e)
        {
            beforeStartChecks.Remove(textBox_sourcePath);
            if (Directory.Exists(textBox_sourcePath.Text)){
                if (readerThread != null)
                    readerThread.Abort();
                collector = new FileCollector(textBox_sourcePath.Text);
                //start the reader thread, so that the time, which is needed by the user to select the other options, can be used to pre select the files
                readerThread = new Thread(() => collector.loadFileList(this));
                readerThread.Start();
                sourceOrPathChanged(sender, e);
                textBox_sourcePath.BackColor = Color.Empty;
                beforeStartChecks.Add(textBox_sourcePath, true);
            }
            else
            {
                checkBox_HardLinks.Enabled = false;
                checkBox_HardLinks.Checked = false;
                textBox_sourcePath.BackColor = Color.OrangeRed;
                beforeStartChecks.Add(textBox_sourcePath, false);
            }
        }

        private void textBox_destPath_TextChanged(object sender, EventArgs e)
        {
            beforeStartChecks.Remove(textBox_destPath);
            if (Directory.Exists(textBox_destPath.Text))
            {
                sourceOrPathChanged(sender, e);
                textBox_destPath.BackColor = Color.Empty;
                beforeStartChecks.Add(textBox_destPath, true);
            }
            else
            {
                checkBox_HardLinks.Enabled = false;
                checkBox_HardLinks.Checked = false;
                textBox_destPath.BackColor = Color.OrangeRed;
                beforeStartChecks.Add(textBox_destPath, false);
            }
        }

        private void textBox_size_TextChanged(object sender, EventArgs e)
        {
            if (selectingFromPreset == false)
                dropdown_preset.SelectedIndex = 0;
            beforeStartChecks.Remove(textBox_size);
            try
            {
                float.Parse(textBox_size.Text.Replace('.', ','));
                beforeStartChecks.Add(textBox_size,true);
                textBox_size.BackColor = Color.Empty;
            }
            catch (Exception)
            {
                beforeStartChecks.Add(textBox_size,false);
                textBox_size.BackColor = Color.OrangeRed;
            }
        }

        private bool selectingFromPreset = false;//is set to true, so that the changes due to preset selection can be made, without resetting the preset selection
        private void dropdown_preset_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (dropdown_preset.Text)
            {
                case CD74:
                    selectingFromPreset = true;
                    textBox_size.Text = "650";
                    comboBox_KindOfSize.SelectedIndex = 0;
                    break;
                case CD80:
                    selectingFromPreset = true;
                    textBox_size.Text = "700";
                    comboBox_KindOfSize.SelectedIndex = 0;
                    break;
                case CD90:
                    selectingFromPreset = true;
                    textBox_size.Text = "800";
                    comboBox_KindOfSize.SelectedIndex = 0;
                    break;
                case DVD5:
                    selectingFromPreset = true;
                    textBox_size.Text = "4,7";
                    comboBox_KindOfSize.SelectedIndex = 1;
                    break;
                case DVD9:
                    selectingFromPreset = true;
                    textBox_size.Text = "8,5";
                    comboBox_KindOfSize.SelectedIndex = 1;
                    break;
                case BD:
                    selectingFromPreset = true;
                    textBox_size.Text = "25";
                    comboBox_KindOfSize.SelectedIndex = 1;
                    break;
                case BDDL:
                    selectingFromPreset = true;
                    textBox_size.Text = "50";
                    comboBox_KindOfSize.SelectedIndex = 1;
                    break;
                default:
                    break;
            }
            Thread.Sleep(50);
            selectingFromPreset = false;
        }

        private void comboBox_KindOfSize_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (selectingFromPreset == false)
                dropdown_preset.SelectedIndex = 0;
        }

        private bool running = false;
        private Thread readerThread = null;
        private FileCollector collector = null;
        private Thread worker = null;
        public delegate void button_START_Click_CALL(object sender, EventArgs e);
        //start worker thread and return to GUI
        internal void button_START_Click(object sender, EventArgs e)
        {
            if (!running)
            {
                running = true;
                button_START.Text = "stop";
                button_sourceFolder.Enabled = false;
                button_destFolder.Enabled = false;
                textBox_sourcePath.Enabled = false;
                textBox_destPath.Enabled = false;
                textBox_size.Enabled = false;
                dropdown_preset.Enabled = false;
                comboBox_KindOfSize.Enabled = false;
                checkBox_HardLinks.Enabled = false;

                workerThread w = new workerThread(this, readerThread, collector, comboBox_KindOfSize.Text, textBox_size.Text, textBox_sourcePath.Text, textBox_destPath.Text, checkBox_HardLinks.Checked);
                worker = new Thread(() => w.gogo());
                worker.Start();
            }
            else
            {
                if (worker != null)
                {
                    worker.Abort();
                    worker = null;
                }
                progressBar.Value = 0;
                running = false;
                button_START.Text = "START";
                button_sourceFolder.Enabled = true;
                button_destFolder.Enabled = true;
                textBox_sourcePath.Enabled = true;
                textBox_destPath.Enabled = true;
                textBox_size.Enabled = true;
                dropdown_preset.Enabled = true;
                comboBox_KindOfSize.Enabled = true;
                checkBox_HardLinks.Enabled = true;
                Logger.Log("--------------------------------------------------------------------------------");
            }
        }

        public delegate void showMessageBoxCALL(String text, String caption, MessageBoxButtons buttons, MessageBoxIcon icon);
        public void showMessageBox(String text, String caption, MessageBoxButtons buttons, MessageBoxIcon icon)
        {
            MessageBox.Show(text, caption, buttons, icon);
        }
        

        /*
         * some functions, which implements drag and drop functionality
         */
        private void textBox_sourcePath_DragDrop(object sender, DragEventArgs e)
        {
            FileInfo file = new FileInfo(((String[])e.Data.GetData(DataFormats.FileDrop))[0]);
            textBox_sourcePath.Text = file.FullName;
        }

        private void textBox_destPath_DragDrop(object sender, DragEventArgs e)
        {
            FileInfo file = new FileInfo(((String[])e.Data.GetData(DataFormats.FileDrop))[0]);
            textBox_destPath.Text = file.FullName;
        }

        private void textBox_Path_DragEnter(object sender, DragEventArgs e)
        {
            //only one selected foldercan be dropped, not files and not more than one folder
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                String[] files = ((String[])e.Data.GetData(DataFormats.FileDrop));
                if (files.Length == 1 && (new FileInfo(files[0])).Extension == "")
                {
                    e.Effect = DragDropEffects.Copy;
                    return;
                }
            }
            e.Effect = DragDropEffects.None;
        }
    }
}
